package cn.safekeeper.guide.admin.controller;

import cn.safekeeper.core.SafeKeeper;
import cn.safekeeper.guide.admin.constant.Constants;
import cn.safekeeper.guide.admin.constant.Msg;
import cn.safekeeper.guide.admin.constant.MsgObj;
import cn.safekeeper.guide.admin.domain.entity.RegisterBody;
import cn.safekeeper.guide.admin.domain.entity.SysMenu;
import cn.safekeeper.guide.admin.domain.entity.SysUser;
import cn.safekeeper.guide.admin.domain.vo.LoginBody;
import cn.safekeeper.guide.admin.service.ISysConfigService;
import cn.safekeeper.guide.admin.service.ISysMenuService;
import cn.safekeeper.guide.admin.service.ISysUserService;
import cn.safekeeper.guide.admin.service.impl.SysPermissionService;
import cn.safekeeper.guide.admin.service.impl.SysRegisterService;
import cn.safekeeper.guide.admin.utils.*;
import cn.safekeeper.guide.admin.utils.ip.IpUtils;
import cn.safekeeper.guide.admin.utils.sign.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;

/**
 * 登录验证
 */
@Slf4j
@RestController
public class LoginController extends BaseController {

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysRegisterService registerService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AsyncLogUtil asyncLogUtil;

    /**
     * 登录方法
     *
     * @return 结果
     */
    @PostMapping("/login")
    public Object login(@Validated @RequestBody LoginBody loginBody, HttpServletRequest request) {
        try {
            boolean captchaOnOff = configService.selectCaptchaOnOff();
            // 验证码开关
            if (captchaOnOff) {
                String validateRet = validateCaptcha(loginBody.getCode(), loginBody.getUuid(),loginBody.getUsername(), request);
                if(StringUtils.isNotEmpty(validateRet)){
                    return error(validateRet);
                }
            }

            //记录日志
            String ipAddr = IpUtils.getIpAddr(request);
            String osName = IpUtils.getOsName(request);
            String browserName = IpUtils.getBrowserName(request);

            //查询用户信息
            SysUser sysUser = userService.selectUserByUserName(loginBody.getUsername());
            if (sysUser == null) {
                asyncLogUtil.recordLoginInfoAsync(loginBody.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists"),
                        ipAddr, osName, browserName);
                return MsgObj.error(Msg.NOT_EXISTS_USER);
            }

            if (!Md5Utils.hash(loginBody.getPassword()).equals(sysUser.getPassword())) {
                asyncLogUtil.recordLoginInfoAsync(loginBody.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"),
                        ipAddr, osName, browserName);
                return MsgObj.error(Msg.PASSWORD_ERROR);
            }

            //更新用户登录信息
            recordLoginInfo(sysUser, ipAddr);

            //记录日志
            asyncLogUtil.recordLoginInfoAsync(loginBody.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"),
                    ipAddr, osName, browserName);

            //调用SafeKeeper框架登录方法，实现权限控制
            SafeKeeper.safeDefault().login(sysUser.getUserId());
        } catch (Exception e) {
            log.error("登录异常", e);
            asyncLogUtil.recordLoginInfoAsync(loginBody.getUsername(), Constants.LOGIN_FAIL, e.getMessage(),
                    IpUtils.getIpAddr(request), IpUtils.getOsName(request), IpUtils.getBrowserName(request));
            return MsgObj.error(Msg.SERVER_BUSY_MSG);
        }
        return MsgObj.success();
    }

    /**
     * 获取用户信息
     * @return 用户信息
     */
    @GetMapping("/getInfo")
    public Object getInfo() {
        SysUser user = getLoginUser();
        if (user == null) {
            return MsgObj.error(Msg.USER_NO_LOGIN);
        }
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        MsgObj msgObj = MsgObj.success();
        msgObj.put("user", user);
        msgObj.put("roles", roles);
        msgObj.put("permissions", permissions);
        return msgObj;
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("/getRouters")
    public Object getRouters() {
        SysUser sysUser = getLoginUser();
        if (sysUser == null) {
            return MsgObj.error(Msg.USER_NO_LOGIN);
        }
        Long userId = sysUser.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return MsgObj.success(menuService.buildMenus(menus));
    }

    @PostMapping("/logout")
    public MsgObj logout(HttpServletRequest request) {
        // 记录用户退出日志
        try {
            asyncLogUtil.recordLoginInfoAsync(getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"),
                    IpUtils.getIpAddr(request), IpUtils.getOsName(request), IpUtils.getBrowserName(request));

            SafeKeeper.safeDefault().logout();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success();
    }

    @PostMapping("/register")
    public MsgObj register(@RequestBody RegisterBody user, HttpServletRequest request) {
        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
            return error("当前系统没有开启注册功能！");
        }
        boolean captchaOnOff = configService.selectCaptchaOnOff();

        // 验证码开关
        if (captchaOnOff) {
            String validateRet = validateCaptcha(user.getCode(), user.getUuid(), user.getUsername(), request);
            if(StringUtils.isNotEmpty(validateRet)){
                return error(validateRet);
            }
        }
        String msg = registerService.register(user, request);
        return StringUtils.isEmpty(msg) ? MsgObj.success() : MsgObj.error(msg);
    }

    /**
     * 校验验证码
     *
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    private String validateCaptcha(String code, String uuid, String userName, HttpServletRequest request) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            asyncLogUtil.recordLoginInfoAsync(userName, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"),
                    IpUtils.getIpAddr(request), IpUtils.getOsName(request), IpUtils.getBrowserName(request));
            return MessageUtils.message("user.jcaptcha.expire");
        }
        if (!code.equalsIgnoreCase(captcha)) {
            asyncLogUtil.recordLoginInfoAsync(userName, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"),
                    IpUtils.getIpAddr(request), IpUtils.getOsName(request), IpUtils.getBrowserName(request));
            return MessageUtils.message("user.jcaptcha.error");
        }
        return "";
    }

    /**
     * 更新用户登录信息
     */
    private void recordLoginInfo(SysUser user, String ip) {
        user.setLoginIp(ip);
        user.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(user);
    }
}
